package com.hilin.test.fs;

import com.hilin.common.util.EntityUtils;
import com.hilin.common.util.IdUtils;
import lombok.extern.slf4j.Slf4j;
import org.freeswitch.esl.client.IEslEventListener;
import org.freeswitch.esl.client.test.FsEventType;
import org.freeswitch.esl.client.transport.event.EslEvent;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;

import java.util.*;

@Slf4j
@Component
public class FsEventHandler implements IEslEventListener {

    private static final Object AGENTS_LOCK = new Object();

    private static final List<String> AGENTS = new ArrayList<>();

    @Autowired(required = false)
    private IFsListener FS_LISTENER;

    /**
     * 保存呼叫信息
     */
    private static final String RK_CC_INFO = "com:hilin:tps:cc:%s";

    /**
     * 中继号码
     */
    private static final String RHK_RELAY_NUMBER = "relayNumber";

    /**
     * agent号码
     */
    private static final String RHK_CALLTYPE = "callType";

    /**
     * 事务id
     */
    private static final String RHK_CALL_ID = "callId";

    /**
     * leg数据字段
     */
    private static final String RHK_LEG_STATUS = "status";
    private static final String RHK_LEG_UUID = "uuid";
    private static final String RHK_LEG_MOB = "mob";

    static {
        for (int i = 0; i < 20; i++) {
            AGENTS.add((1000 + i) + "");
        }
    }

    public static void setAgents(List<String> agents) {
        synchronized (AGENTS_LOCK) {
            FsEventHandler.AGENTS.clear();
            FsEventHandler.AGENTS.addAll(agents);
        }
    }

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Override
    public void eventReceived(EslEvent event) {
        synchronized (AGENTS_LOCK) {
            if (FsEventType.HEARTBEAT.name().equalsIgnoreCase(event.getEventName())) {
                return;
            }
            // 主叫号码
            String inMob = event.getEventHeaders().get("Caller-ANI");
            if (ObjectUtils.isEmpty(inMob) || inMob.equals("0000000000")) {
                return;
            }
            // 被叫号码
            String toMob = event.getEventHeaders().get("Caller-Destination-Number");

            String uuid = event.getEventHeaders().get("Unique-ID");
            if (ObjectUtils.isEmpty(uuid)) {
                return;
            }
            // 主叫号码是否是内线号码
            boolean inMobInbound = isAgent(inMob);
            String callType = inMobInbound ? CCEvent.CALL_TYPE_CALLIN : CCEvent.CALL_TYPE_CALLOUT;
            FsEventType eventName = FsEventType.valueOf(event.getEventName());
            String callId = IdUtils.DEFAULT.gen().toString();
            callId = setCallId(inMob, callId) ? callId : getRedisCallId(inMob);
            switch (eventName) {
                case RECORD_STOP:
                    log.info("【录音】录音完成 {}", EntityUtils.toJsonString(event.getEventHeaders()));
                    break;
                case RECORD_START:
                    log.info("【录音】录音开始 {}", EntityUtils.toJsonString(event.getEventHeaders()));
                    break;
                case CHANNEL_CREATE:
                    if (inMobInbound) {
                        // 呼出
                        setHValue(inMob, RHK_CALLTYPE, callType + "");
                        String callerDirection = event.getEventHeaders().get("Caller-Direction");
                        if ("inbound".equals(callerDirection)) {
                            // 这个是aleg创建
                            if (log.isInfoEnabled()) {
                                log.info("【呼出】主叫号码:{}  被叫号码:{}", inMob, toMob);
                            }
                            // aleg是主叫到中继号码
                            putRedisALegData(inMob, RHK_LEG_UUID, uuid);
                            putRedisALegData(inMob, RHK_LEG_STATUS, "open");
                            FS_LISTENER.callout(CCEvent.builder()
                                    .id(IdUtils.DEFAULT.gen().toString())
                                    .callId(callId)
                                    .callType(callType)
                                    .eventType(CCEvent.EVENT_TYPE_CALLOUT)
                                    .number(toMob)
                                    .agent(inMob)
                                    .build());
                        } else {
                            // 这个是bleg创建
                            if (log.isInfoEnabled()) {
                                log.info("【呼出】主叫号码:{}  被叫号码:{}", inMob, toMob);
                            }
                            // aleg是主叫到中继号码
                            putRedisBLegData(inMob, RHK_LEG_UUID, uuid);
                            putRedisBLegData(inMob, RHK_LEG_STATUS, "open");
                        }
                        putRedisBLegData(inMob, RHK_LEG_MOB, inMob);
                    } else {
                        boolean isALeg = setRelayNumber(inMob, toMob);
                        if (isALeg) {
                            // aleg是主叫到中继号码
                            putRedisALegData(inMob, RHK_LEG_UUID, uuid);
                            putRedisALegData(inMob, RHK_LEG_STATUS, "open");
                            if (log.isInfoEnabled()) {
                                log.info("【呼入】 创建aleg 主叫号码:{}  中继号码:{}  aleg-Unique-ID:{}", inMob, toMob, uuid);
                            }
                            FS_LISTENER.call(CCEvent.builder()
                                    .id(IdUtils.DEFAULT.gen().toString())
                                    .callId(callId)
                                    .callType(callType)
                                    .eventType(CCEvent.EVENT_TYPE_CALL)
                                    .number(inMob)
                                    .relayNumber(toMob)
                                    .build());
                        } else {
                            if (!ObjectUtils.isEmpty(getRedisBLegData(inMob, RHK_LEG_UUID))) {
                                // 不为空，说明是席位切换
                                String oldAgent = Optional.ofNullable(getRedisBLegData(inMob, RHK_LEG_MOB)).orElse("");
                                if (log.isInfoEnabled()) {
                                    log.info("【切换】 当前席位:{}  切换席位:{}  aleg-Unique-ID:{}", oldAgent, toMob, uuid);
                                }
                                FS_LISTENER.switchAgent(CCEvent.builder()
                                        .id(IdUtils.DEFAULT.gen().toString())
                                        .callId(callId)
                                        .callType(callType)
                                        .eventType(CCEvent.EVENT_TYPE_SWITCH_AGENT)
                                        .number(inMob)
                                        .agent(toMob)
                                        .oldAgent(oldAgent)
                                        .relayNumber(getRelayNumber(inMob))
                                        .build());
                                putRedisCallId(inMob, IdUtils.DEFAULT.gen().toString());
                            } else {
                                // 呼入
                                if (log.isInfoEnabled()) {
                                    log.info("【呼入】 创建bleg 主叫号码:{}  被叫号码:{}  bleg-Unique-ID:{}", inMob, toMob, uuid);
                                }
                                FS_LISTENER.callin(CCEvent.builder()
                                        .id(IdUtils.DEFAULT.gen().toString())
                                        .callId(callId)
                                        .callType(callType)
                                        .eventType(CCEvent.EVENT_TYPE_CALLIN)
                                        .number(inMob)
                                        .agent(toMob)
                                        .relayNumber(getRelayNumber(inMob))
                                        .eventTime(new Date())
                                        .build());
                            }
                            putRedisBLegData(inMob, RHK_LEG_STATUS, "open");
                            putRedisBLegData(inMob, RHK_LEG_UUID, uuid);
                            putRedisBLegData(inMob, RHK_LEG_MOB, toMob);
                        }
                    }
                    break;
                case CHANNEL_ANSWER:
                    if (isBLeg(event)) {
                        // 用户席位leg的事件，处理
                        if (log.isInfoEnabled()) {
                            log.info("【呼入】 接听 主叫号码:{}  被叫号码:{}  bleg-Unique-ID:{}", inMob, toMob, uuid);
                        }
                        if (!inMobInbound) {
                            FS_LISTENER.answer(CCEvent.builder()
                                    .id(IdUtils.DEFAULT.gen().toString())
                                    .callId(callId)
                                    .eventTime(new Date())
                                    .callType(callType)
                                    .eventType(CCEvent.EVENT_TYPE_ANSWER)
                                    .number(inMob)
                                    .agent(toMob)
                                    .relayNumber(getRelayNumber(inMob))
                                    .build());
                        } else {
                            FS_LISTENER.answer(CCEvent.builder()
                                    .callType(callType)
                                    .eventType(CCEvent.EVENT_TYPE_ANSWER)
                                    .number(toMob)
                                    .agent(inMob)
                                    .id(IdUtils.DEFAULT.gen().toString())
                                    .callId(callId)
                                    .eventTime(new Date())
                                    .build());
                        }
                    } else if (isALeg(event)) {
                        // 中继leg的事件，处理
                        if (log.isInfoEnabled()) {
                            log.info("【呼入】 接听 主叫号码:{}  中继号码:{}  aleg-Unique-ID:{}", inMob, toMob, uuid);
                        }
                    }
                    break;
                case CHANNEL_HANGUP_COMPLETE:
                    if (isBLeg(event)) {
                        // 用户席位leg的事件，处理
                        if (log.isInfoEnabled()) {
                            log.info("【挂断】 主叫号码:{}  被叫号码:{}  bleg-Unique-ID:{}", inMob, toMob, uuid);
                        }
                        putRedisBLegData(inMob, RHK_LEG_STATUS, "close");
                    } else if (isALeg(event)) {
                        // 中继席位leg的事件
                        if (log.isInfoEnabled()) {
                            log.info("【挂断】 主叫号码:{}  中继号码:{}  aleg-Unique-ID:{}", inMob, toMob, uuid);
                        }
                        putRedisALegData(inMob, RHK_LEG_STATUS, "close");
                    }
                    // 两个leg都关闭 认为是通话结束
                    if ("close".equals(Optional.ofNullable(getRedisALegData(inMob, RHK_LEG_STATUS)).orElse("close"))
                            && "close".equals(Optional.ofNullable(getRedisBLegData(inMob, RHK_LEG_STATUS)).orElse("close"))) {
                        if (log.isInfoEnabled()) {
                            log.info("【挂断】 通话结束 主叫号码:{}  被叫号码:{}", inMob, getRedisBLegData(inMob, RHK_LEG_MOB));
                        }
                        if (inMobInbound) {
                            FS_LISTENER.hangup(CCEvent.builder()
                                    .callType(callType)
                                    .eventType(CCEvent.EVENT_TYPE_HANGUP)
                                    .number(toMob)
                                    .agent(inMob)
                                    .id(IdUtils.DEFAULT.gen().toString())
                                    .callId(callId)
                                    .eventTime(new Date())
                                    .build());
                        } else {
                            FS_LISTENER.hangup(CCEvent.builder()
                                    .callType(callType)
                                    .eventType(CCEvent.EVENT_TYPE_HANGUP)
                                    .number(inMob)
                                    .agent(getRedisBLegData(inMob, RHK_LEG_MOB))
                                    .relayNumber(getRelayNumber(inMob))
                                    .id(IdUtils.DEFAULT.gen().toString())
                                    .callId(callId)
                                    .eventTime(new Date())
                                    .build());
                        }
                        delAllMob(inMob);
                    }
                    break;
            }
            mongoTemplate.save(event.getEventHeaders(), "fs");
        }
    }

    @Autowired
    private MongoTemplate mongoTemplate;

    @Override
    public void backgroundJobResultReceived(EslEvent event) {

    }

    public static boolean isAgent(String mob) {
        synchronized (AGENTS_LOCK) {
            for (String agent : AGENTS) {
                if (agent.equals(mob)) {
                    return true;
                }
            }
            return false;
        }

    }

    public boolean isALeg(EslEvent event) {
        // 主叫号码
        String inMob = event.getEventHeaders().get("Caller-ANI");
        return event.getEventHeaders().getOrDefault("Unique-ID", "").equals(getRedisALegData(inMob, RHK_LEG_UUID));
    }

    public boolean isBLeg(EslEvent event) {
        // 主叫号码
        String inMob = event.getEventHeaders().get("Caller-ANI");
        return event.getEventHeaders().getOrDefault("Unique-ID", "").equals(getRedisBLegData(inMob, RHK_LEG_UUID));
    }

    public void putRedisCallId(String mob, String transactionId) {
        redisHashPut(mob, RHK_CALL_ID, transactionId);
    }

    public String getRedisCallId(String mob) {
        return redisHashGet(mob, RHK_CALL_ID);
    }

    public void putRedisALegData(String mob, String key, String value) {
        redisHashPut(mob, "aleg_" + key, value);
    }

    public String getRedisALegData(String mob, String key) {
        return redisHashGet(mob, "aleg_" + key);
    }

    public void putRedisBLegData(String mob, String key, String value) {
        redisHashPut(mob, "bleg_" + key, value);
    }

    public String getRedisBLegData(String mob, String key) {
        return redisHashGet(mob, "bleg_" + key);
    }

    public String redisHashGet(String mob, String hKey) {
        return (String) redisTemplate.opsForHash().get(String.format(RK_CC_INFO, mob), hKey);
    }

    public void redisHashPut(String mob, String hKey, String hValue) {
        redisTemplate.opsForHash().put(String.format(RK_CC_INFO, mob), hKey, hValue);
    }

    public void delAllMob(String mob) {
        redisTemplate.delete(String.format(RK_CC_INFO, mob));
    }

    public boolean setRelayNumber(String mob, String relayNumber) {
        return redisTemplate.opsForHash().putIfAbsent(String.format(RK_CC_INFO, mob), RHK_RELAY_NUMBER, relayNumber);
    }

    public boolean setCallId(String mob, String callId) {
        return redisTemplate.opsForHash().putIfAbsent(String.format(RK_CC_INFO, mob), RHK_CALL_ID, callId);
    }

    public String getRelayNumber(String mob) {
        return getHValue(mob, RHK_RELAY_NUMBER);
    }

    public String getHValue(String mob, String hKey) {
        return (String) redisTemplate.opsForHash().get(String.format(RK_CC_INFO, mob), hKey);
    }

    public void setHValue(String mob, String hKey, String hValue) {
        redisTemplate.opsForHash().put(String.format(RK_CC_INFO, mob), hKey, hValue);
    }


    // 存放aleg信息
    public void setAleg(String aLegUuid, String inMob, Map<String, String> map) {

    }
}
